FP Workshop - 0. FP Basic

Chapter 0: FP Basic

함수형 프로그래밍을 접하기 전에 알아야할 기본 지식들

Imperative

Imperative

Functional

Functional

1. Pure Function (순수함수)

순수함수란

  • 같은 input ⇒ 같은 output
  • 언제 어디서 실행하든지 항상 같은 결과
  • 부수효과(side effect)가 없음
function PureAdd(a, b) {
  return a + b;
}

let b = 1;
function NonPureAdd(a) {
  return a + b;
}

function SideEffectAdd(a, b) {
  console.log('hi!');
  return a + b;
}

2. First Class Function (일급함수)

함수를 값으로 다룰 수 있다

// Can assign to variable
const add = (a, b) => a + b;

// Can pass function as parameter
[1, 2, 3].reduce(add);

// Function can return another function
const subtract = (a) => (b) => a - b;

3. Iterator Protocol

객체가 iterable 하기 위해서는 iterable protocol 을 따라야 합니다.

// Iterate Map
for (const el of new Map([
  ['a', 1],
  ['b', 2],
])) {
  console.log(el);
}

// Iterate Set
for (const el of new Set([1, 2, 3])) {
  console.log(el);
}

// Iterate Array
for (const el of ['lodash', 'ramda', 'fxts']) {
  console.log(el);
}

// Iterate plain object
const obj = { a: 1, b: 2 };
for (const el of obj) {
  console.log(el); // Uncaught TypeError: obj is not iterable
}

기본 객체를 iterable 하도록 만들어 봅시다.

// Declare non iterable object
const obj = {
  a: 1,
  b: 2,
  c: 3,
};

// Set [Symbol.iterator] property
obj[Symbol.iterator] = function () {
  let i = 0;
  const values = Object.values(this);

  return {
    next() {
      return i == values.length ? { done: true } : { value: values[i++], done: false };
    },
    [Symbol.iterator]() {
      return this;
    }, // well-formed iterator
  };
};

// Now we can iterate `obj` with `for of` statement.
for (const el of obj) {
  console.log(el); // 1 2 3
}

4. Generator

제너레이터를 사용하면 iterable 한 객체를 쉽게 구현할 수 있습니다.

function* gen() {
  yield 1;
  yield 2;
  yield 3;
}

const iter = gen();

iter.next(); // { value: 1, done: false }
iter.next(); // { value: 2, done: false }
iter.next(); // { value: 3, done: false }
iter.next(); // { value: undefined, done: true }

제너레이터를 응용하면 무한으로 iterable 한 iterator 를 만들 수 있습니다.

function *infinite() {
  let i = -1;
  while (true) {
		yield ++i;
  }
}

const iter = infinite();
iter.next(); // { value: 1, done: false }
iter.next(); // { value: 2, done: false }
iter.next(); // { value: 3, done: false }
...